package com.example.shiro.config;

import com.example.shiro.filter.ShiroAuthenticationFilter;
import com.example.shiro.util.MyRealm;
import com.example.shiro.util.SHA256Util;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description : Shiro 配置类
 * @Author : Bruce Lee
 * @CreateTime : 2024/5/28
 */


@Configuration
public class ShiroConfig {

    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private String redisPort;

    @Value("${spring.redis.expireTime}")
    private Integer expireTime;

    /* 密码匹配器 */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
        // 散列算法:这里使用SHA256算法(是否加盐-可选择);
        shaCredentialsMatcher.setHashAlgorithmName(SHA256Util.HASH_ALGORITHM_NAME);
        // 散列的次数，比如散列两次，相当于 md5(md5(""));
//        shaCredentialsMatcher.setHashIterations(SHA256Util.HASH_ITERATIONS);
        return shaCredentialsMatcher;
    }

    /* 自定义认证及授权过程 */
    @Bean
    public MyRealm shiroRealm() {
        MyRealm shiroRealm = new MyRealm();
        // 注册密码匹配器(默认直接匹配，不支持加密)
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealm;
    }

    @Bean
    public DefaultWebSecurityManager securityManager() {
        // 创建DefaultWebSecurityManager对象
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置自定义的Realm
        securityManager.setRealm(shiroRealm());
        // 设置自定义的sessionManager
        securityManager.setSessionManager(sessionManager());
        // 设置基于redis的cacheManager
        securityManager.setCacheManager(cacheManager());
        return securityManager;
    }

    @Bean
    public DefaultWebSessionManager sessionManager() {  // 配置默认的sesssion管理器
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // 设置全局session过期时间
        sessionManager.setGlobalSessionTimeout(600 * 1000);
        // 设置自定义的 sessionDAO
        sessionManager.setSessionDAO(sessionDAO());
//        Collection<SessionListener> listeners = new ArrayList<>();
//        // 配置自定义的 sessionListener
//        listeners.add(new BDSessionListener());
//        sessionManager.setSessionListeners(listeners);
        return sessionManager;
    }


    @Bean
    public SessionDAO sessionDAO() {
        // 配置自定义的 sessionDAO: 默认key采用字符串序列化方式、value采用jdk序列化方式
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
        // shiro 内置的基于内存sessionDAO
//        return new MemorySessionDAO();
    }


    /* 用于shiro-redis 连接redis服务器 */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        // 高版本的shiro-redis，取消setPort方法，需要将Port和Host写在一起
        redisManager.setHost(redisHost + ":" + redisPort);
        // 配置过期时间
        redisManager.setTimeout(expireTime);
        return redisManager;
    }

    /* 基于redis自定义cacheManager */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactory(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 自定义拦截器
        Map<String, Filter> customFilterMap = new LinkedHashMap<>();
        customFilterMap.put("shiroAuthenticationFilter", new ShiroAuthenticationFilter());
        // 注册自定义拦截器
        shiroFilterFactoryBean.setFilters(customFilterMap);

        // 拦截器，配置访问权限 必须是LinkedHashMap，因为它必须保证有序。滤链定义，从上向下顺序执行，一般将 /**放在最为下边
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 配置过滤:不会被拦截的链接(匿名访问)
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/userLogin/**", "anon");
        // 最终执行自定义拦截器
        filterChainDefinitionMap.put("/**", "shiroAuthenticationFilter");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }


}
